package control;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.swing.plaf.SliderUI;

import model.general.LoadImage;
import model.general.Location;
import model.general.Util;
import model.objects.Boat;
import model.objects.FunnyObject;
import model.objects.Hook;
import model.objects.IAnimateItems;
import model.objects.IAnimateMainActor;
import model.objects.IAnimateSubActor;
import model.objects.Lighting;
import model.observer.Obseverable;
import model.option.OptionAddLife;
import sound.ILoadMusic;
import sound.LoadMusic;
import sound.Sounds;
import view.HeightScoreTable;
import view.Map;

public class ControlGame implements IControlGame, Runnable {
	private Map map;
	private List<IAnimateItems> listItems = new ArrayList<IAnimateItems>();
	private IAnimateMainActor boat;
	private Lighting lighting;

	private int QUATITY_ITEMS = 7;
	private int QUATITY_FISH = 10;
	private int QUATITY_BAD_ITEMS = 1;
	private int QUATITY_GOOD_ITEMS = 1;
	private int GAME_SPEED = 1;
	private int MAX_LEVEL = 3;
	private int LEVEL_NOW = 1;
	private int MAX_SCORE_LEVEL_NOW = 5;

	private Thread animator; // the thread that performs the animation
	private boolean running = false; // used to stop the animation thread
	private boolean isPaused = false;
	private boolean isNextLevel = false;
	private boolean isWon = false;

	private static int count = 0;
	private long period; // period between drawing in _nanosecs_

	private long gameStartTime; // when the game started
	private int timeSpentInGame;

	private char stateGame = Util.BEFORE_START_STATE;

	// used at game termination
	private boolean gameOver = false;
	private int score = 0;
	private int speed = Util.DEFAULT_SPEED_MOVE;

	// for displaying messages
	private Font msgsFont;
	private FontMetrics metrics;

	// off-screen rendering
	private Graphics dbg;
	private Image dbImage = null;

	// holds the background image
	private BufferedImage bgImage = null;

	private Random rand = new Random();

	private boolean isTunrnOnMusic = true;
	private boolean playingMusic = false;
	private ILoadMusic music_theme = new LoadMusic(Sounds.THEME, isTunrnOnMusic);
	private ILoadMusic music_throw_hook = new LoadMusic(Sounds.THROW_HOOK,
			false);

	public ControlGame(Map map) {
		this.map = map;
		System.out.println(map == null);
		System.out.println(map.getWidth() + " ---- " + map.getHeight());
		// load the background image
		LoadImage imsLoader = new LoadImage();
		bgImage = imsLoader.getbufferImage("bg.jpg");

		// set up message font
		msgsFont = new Font("SansSerif", Font.BOLD, 24);
		metrics = map.getFontMetrics(msgsFont);
		boat = new Boat(new Location(0, 80), "boat-left.png", "boat-right.png",
				map);
		lighting = new Lighting(new Location(0, 0), "lighting.png",
				"lightning-icon.png", map, (Boat) boat);
		playMusic();

	}

	public void gameOver() {
		stateGame = Util.LOSE_STATE;
		gameOver = true;
	}

	public void addNotify()
	// wait for the JPanel to be added to the JFrame before starting
	{
		startGame(); // start the thread
	}

	@Override
	public void startGame() {
		if (animator == null || !running) {

			animator = new Thread(this);
			animator.start();
			stateGame = Util.PLAYING_STATE;
		}
	}

	// ------------- game life cycle methods ------------
	// called by the JFrame's window listener methods
	@Override
	public void pauseGame() {
		isPaused = true;
		stateGame = Util.PAUSE_STATE;
		stopMusic();
	}

	@Override
	public void resumeGame() {
		isPaused = false;
		stateGame = Util.PLAYING_STATE;
		playMusic();
	}

	@Override
	public void stopGame() {
		running = false;
		stateGame = Util.STOP_STATE;
		stopMusic();
	}

	@Override
	public void run() {
		running = true;

		new CreateFish(QUATITY_FISH, boat, listItems, map, Util.ID_FISH_ITEM,
				speed).start();
		new CreateFish(QUATITY_BAD_ITEMS, boat, listItems, map,
				Util.ID_BAD_ITEM_SUB_SCORE, speed).start();
		new CreateFish(QUATITY_GOOD_ITEMS, boat, listItems, map,
				Util.ID_GOOD_ITEM_ADD_lIFE, speed).start();

		while (running) {
			gameUpdate();
			gameRender();
			paintScreen();
		}

		try {
			Thread.sleep(50);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void gameUpdate() {
		if (!isPaused && !gameOver) {
			for (int i = 0; i < listItems.size(); i++) {
				listItems.get(i).move();
			}
			lighting.move();
		}
		map.updateAllElement();
	} // end of gameUpdate()

	private void gameRender() {
		if (dbImage == null) {
			dbImage = map.createImage(800, 600);
			if (dbImage == null) {
				System.out.println("dbImage is null");
				return;
			} else
				dbg = dbImage.getGraphics();
		}

		// draw the background: use the image or a black colour
		if (bgImage == null) {
			dbg.setColor(Color.black);
			dbg.fillRect(0, 0, map.getWidth(), map.getHeight());
		} else
			dbg.drawImage(bgImage, 0, 0, map);

		// draw game elements

		if (isPaused) {
			if (isNextLevel) {
				map.paintGameLevelUp(dbg);
			} else {
				if (isWon) {
					map.paintGameWonWarning(dbg);
				} else {
					map.paintGamePausedWarning(dbg);
				}
			}
		} else {
			map.paintSomethingFun(dbg);
			map.paintStatusBar(dbg);
		}
		boat.show(dbg);
		lighting.show(dbg);
		for (int i = 0; i < listItems.size(); i++) {
			listItems.get(i).show(dbg);
		}

		if (gameOver)
			gameOverMessage(dbg);
	} // end of gameRender()

	private void gameOverMessage(Graphics g)
	// center the game-over message in the panel
	{
		String msg = "Game Over. Your score: " + score;

		int x = (map.getWidth() - metrics.stringWidth(msg)) / 2;
		int y = (map.getHeight() - metrics.getHeight()) / 2;
		g.setColor(Color.red);
		g.setFont(msgsFont);
		g.drawString(msg, x, y);
	} // end of gameOverMessage()

	private void paintScreen()
	// use active rendering to put the buffered image on-screen
	{
		Graphics g;
		try {
			g = map.getGraphics();
			if ((g != null) && (dbImage != null))
				g.drawImage(dbImage, 0, 0, null);
			g.dispose();
		} catch (Exception e) {
			System.out.println("Graphics context error: " + e);
		}
	} // end of paintScreen()

	// control for element in the game
	public void moveBoatLeft() {
		if (!isPaused && !gameOver) {
			boat.moveLeft();
		}
	}

	public void moveBoatRight() {
		if (!isPaused && !gameOver) {
			boat.moveRight();
		}
	}

	public void throwHook() {
		if (!isPaused && !gameOver) {
			boat.moveHook();
			if (isTunrnOnMusic)
				music_throw_hook.playMusic();
		}
	}

	@Override
	public IAnimateMainActor getBoat() {
		return boat;
	}

	public void stopMusic() {
		if (playingMusic) {
			music_theme.stopMusic();
			playingMusic = false;
		}
	}

	public void playMusic() {
		System.out.println("is turn on " + isTunrnOnMusic + " playing "
				+ playingMusic);
		if (isTunrnOnMusic && !playingMusic) {
			System.out.println("play music");
			music_theme.playMusic();
			playingMusic = true;
		}
	}

	@Override
	public void changeStateMusic() {
		this.isTunrnOnMusic = !isTunrnOnMusic;
		if (isTunrnOnMusic) {
			playingMusic = false;
			playMusic();
		} else {
			playingMusic = true;
			stopMusic();

		}

	}

	public void levelUp() {
		listItems.clear();

		QUATITY_BAD_ITEMS += 2;
		QUATITY_FISH += 2;
		QUATITY_GOOD_ITEMS += 1;
		QUATITY_ITEMS += 5;

		this.startGame();
	}

	@Override
	public void checkLevel(int score, int life) {
		// neu life <= 0 thi ket thuc game
		if (life <= 0) {
			gameOver();
		} else {
			if (score >= MAX_SCORE_LEVEL_NOW && LEVEL_NOW != MAX_LEVEL) {
				LEVEL_NOW++;
				MAX_SCORE_LEVEL_NOW += 5;
				isNextLevel = true;
				pauseGame();// lai ko ctrl space :(
				increaseSpeedItems(this.speed += 10);
				stopMusic();
				stateGame = Util.LEVEL_UP_STATE;
			}
			if (LEVEL_NOW == MAX_LEVEL) {
				LEVEL_NOW = 1;
				isWon = true;
				stateGame = Util.WON_STATE;
				dereaseSpeedItems(Util.DEFAULT_SPEED_MOVE);
				boat = new Boat(new Location(0, 80), "boat-left.png",
						"boat-right.png", map);
			}
		}

	}

	@Override
	public void nextGame() {
		isNextLevel = false;
	}

	@Override
	public void heightScore() {
		isWon = false;
		HeightScoreTable h = new HeightScoreTable();
	}

	private void increaseSpeedItems(int speed) {
		for (int i = 0; i < listItems.size(); i++) {
			listItems.get(i).setSpeed(speed);
		}
	}

	private void dereaseSpeedItems(int speed) {
		for (int i = 0; i < listItems.size(); i++) {
			listItems.get(i).setSpeed(speed);
		}
	}

	@Override
	public char getStateGame() {
		return stateGame;
	}
}
